package com.lxd.mq;

import com.lxd.common.constants.RabbitMQConstants;
import com.lxd.common.model.StandardReport;
import com.lxd.common.utils.JsonUtil;
import com.lxd.config.RabbitMQConfig;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;

/**
 * @Author Dongdong
 * @注释
 */

@Component
@Slf4j
public class PreSendListener {
    @Autowired
    private RestTemplate restTemplate;

    private static final String SUCCESS = "success";
    @Autowired
    private RabbitTemplate mq;

    // 重试的时间间隔。
    private int[] delayTime = {0,15000,30000,60000,300000};

    /**
     * 监听 推送模块的消息，进行第一次推送报告
     * @param report  状态报告
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = RabbitMQConstants.SMS_PUSH_REPORT)//监听第一次推送的队列
    public void listen(StandardReport report, Message message, Channel channel) throws IOException {
        String url = report.getCallbackUrl();
        if (StringUtils.isEmpty(url)) {
            log.info("【推送模块】 用户的回调地址url为空");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            return;
        }
        //1、第一次推送
        boolean flag = pushReport(report);
        //2、是否需要重新推送
        isResend(report, flag);

        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        log.info("【推送模块】 手动ack");

    }

    /**
     * 监听延迟队列，（延迟队列的消息是 第一次推送失败的消息），并进行重新发送
     * @param report 消息
     */
    @RabbitListener(queues = RabbitMQConfig.DELAYED_QUEUE)
    public void delayedConsume(StandardReport report, Channel channel,Message message) throws IOException {
        // 1、发送状态报告
        boolean flag = pushReport(report);

        // 2、判断状态报告发送情况
        isResend(report, flag);

        // 手动ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        log.info("【推送模块-延迟交换机】 手动ack");
    }

    /**
     * 判断第一次是否发送成功，如果失败，则将消息放入延迟交换机
     * @param report
     * @param flag
     */
    private void isResend(StandardReport report, boolean flag) {
        if (flag){
            log.info("【推送模块】 第1次推送成功！");

        }else {
            //需要重新推送！
            log.info("【推送模块】 开始第{}次推送！",report.getReTryCount()+1);
            report.setReTryCount(report.getReTryCount()+1);//修改重试次数
            if (report.getReTryCount()>=5){
                log.info("【推送模块】 重试次数超过4次，结束");
                return;
            }

            //发送到延迟交换机
            log.info("【推送模块-重试】 正在发送至延迟交换机");
            mq.convertAndSend(RabbitMQConfig.DELAYED_EXCHANGE, "", report, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    // 设置延迟时间
                    message.getMessageProperties().setDelay(delayTime[report.getReTryCount()]);
                    return message;
                }
            });
        }

    }

    /**
     *  第一次推送状态报告
     * @param report  要推送的报告
     * @return 是否推送成功
     */
    public boolean pushReport(StandardReport report) {
        boolean flag = false;//是否发送出去

        String body = JsonUtil.obj2JSON(report);
//        log.info("【推送模块-推送状态报告】  数据转换json成功");.

        HttpHeaders httpHeaders = new HttpHeaders();//设置请求头
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);


        try {
            log.info("【推送模块-推送状态报告】 第{}次推送状态报告开始！report = {}",report.getReTryCount() + 1,report);
            String result = restTemplate.postForObject("http://" + report.getCallbackUrl(), new HttpEntity<>(body, httpHeaders), String.class);
            flag = SUCCESS.equals(result);
        } catch (RestClientException e) {
            e.printStackTrace();
        }

        return flag;
    }

}
